#pragma once

// 对外提供服务编程的类

#include "acceptor.h"
#include "callbacks.h"
#include "event_loop.h"
#include "event_loop_thread_pool.h"
#include "inet_address.h"
#include "noncopyable.h"
#include "tcp_connection.h"
#include "buffer.h"

#include <atomic>
#include <functional>
#include <memory>
#include <string>
#include <unordered_map>

// 对外的服务器编程使用的类
class TcpServer : noncopyable {
  public:
    using ThreadInitCallback = std::function<void(EventLoop *)>;

    enum Option {
        kNoReusePort,
        kReusePort,
    };

    TcpServer(EventLoop *loop, const InetAddress &listen_addr, const std::string &name_arg,
             Option option = kNoReusePort);

    ~TcpServer();
    void set_thread_init_callback(const ThreadInitCallback &cb) { thread_init_callback_ = cb; }
    void set_connection_callback(const ConnectionCallback &cb) { connection_callback_ = cb; }
    void set_message_callback(const MessageCallback &cb) { message_callback_ = cb; }
    void set_write_complete_callback(const WriteCompleteCallback &cb) {
        write_complete_callback_ = cb;
    }

    // 设置底层subloop的个数
    void set_thread_num(int num_threads);

    // 开启服务器监听
    void start();

  private:
    void new_connection(int sockfd, const InetAddress &peer_addr);
    void remove_connection(const TcpConnectionPtr &conn);
    void remove_connection_in_loop(const TcpConnectionPtr &conn);

    using ConnectionMap = std::unordered_map<std::string, TcpConnectionPtr>;

    EventLoop *loop_; // base_loop 用户定义的loop

    const std::string ip_port_;
    const std::string name_;

    std::unique_ptr<Acceptor> acceptor_; // 运行在mainloop,任务监听新连接事件

    std::shared_ptr<EventLoopThreadPool> thread_pool_; // one loop per thread

    ConnectionCallback connection_callback_;        // 有新连接的回调
    MessageCallback message_callback_;              // 有读写消息的回调
    WriteCompleteCallback write_complete_callback_; // 消息发送完成后的回调

    ThreadInitCallback thread_init_callback_; // loop线程初始化的回调

    std::atomic_int started_;

    int next_conn_id_;
    ConnectionMap connections_; // 保存所有连接
};